#!/user/bin/env set PYTHONIOENCODING=utf-8 && python -u
# -*- coding: utf-8 -*-

import re

from .primitives import Primitives

from collections.abc import MutableMapping

class PropertyLikeDict(MutableMapping):

    def __init__(self, data=None, **kwargs):
        self._store = dict()
        if data is None:
            data = {}
        self.update(data, **kwargs)

    def __compile__(self, property_path):
        _properties = []
        _pattern = re.compile('\[(\d+)\]')
        def _append(_property, _pos):
            _match = _pattern.search(_property, _pos)
            if _match:
                if _pos == 0:
                    _properties.append(_property[_pos:_match.start()])
                _properties.append(int(_match.group(1)))
                _append(_property, _match.end())
            elif _pos == 0:
                _properties.append(_property)
            elif _pos < len(_property):
                raise KeyError(_property)
        for _property in property_path.split('.'):
            _append(_property, 0)
        return _properties

    def __getitem__(self, property_path):
        _properties = self.__compile__(property_path)
        _context = self._store
        for _property in _properties:
            _context = _context[_property]
        return _context

    def __setitem__(self, property_path, property_value):
        _properties = self.__compile__(property_path)
        _context = self._store
        for _property in _properties[:-1]:
            _context = _context[_property]
        _context[_properties[-1]] = property_value

    def __delitem__(self, property_path):
        _properties = self.__compile__(property_path)
        _context = self._store
        for _property in _properties[:-1]:
            _context = _context[_property]
        del _context[_properties[-1]]

    def __iter__(self):
        return ( key for key in self._store.keys() )

    def __len__(self):
        return len(self._store)

    def __contains__(self, property_path):
        return self[property_path] is not None

    def __eq__(self, other):
        if Primitives.is_dict(other):
            other = PropertyLikeDict(other)
        else:
            return NotImplemented
        return self._store == other._store

    def copy(self):
        return PropertyLikeDict(self._store)

    def __repr__(self):
        return str(self._store)

class Dictionaries:

    @staticmethod
    def rename(dictionary=None, key_transformer=str.lower):
        return { key_transformer(key): value for key, value in dictionary.items() } if Primitives.is_dict(dictionary) else dictionary

    @staticmethod
    def clone_or_new(dictionary=None):
        return dictionary.copy() if Primitives.is_dict(dictionary) else {}

    @staticmethod
    def merge_if_absent(source=None, target=None):
        if Primitives.is_dict(source) and Primitives.is_dict(target):
            for key, value in source.items():
                if key not in target:
                    if value is None:
                        del target[key]
                    else:
                        target[key] = value
